package cn.felord.socket.core;

import cn.felord.socket.messaging.*;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIONamespace;
import com.corundumstudio.socketio.SocketIOServer;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Optional;

/**
 * The type Simple web socket messaging template.
 *
 * @author dax
 * @since 2019 /4/21 17:00
 */
@Component
public class SimpleWebSocketMessagingTemplate extends AbstractWebSocketMessagingTemplate<String> {
    @Resource
    private SocketIOServer socketIOServer;
    @Resource
    private ClientRepository clientRepository;
    private DestinationResolver<String> stringDestinationResolver = new SimpleDestinationResolver();

    /**
     * Instantiates a new Simple web socket messaging template.
     */
    public SimpleWebSocketMessagingTemplate() {
        setDefaultDestination("/");
    }

    @Override
    protected void doBroadcast(String destination, Message<?> message) {


        Symbol symbol = stringDestinationResolver.resolve(destination);
        String eventName = Optional.of(symbol.getEventName()).get();
        String namespace = Optional.of(symbol.getNamespace()).get();
        SocketIONamespace socketIONamespace = obtainNamespace("/" + namespace);
        addEventListener(socketIONamespace, eventName, Message.class);
        socketIONamespace.getBroadcastOperations().sendEvent(eventName, message);

    }

    @Override
    protected <O> void doBroadcast(String destination, O payload) {
        MessageConverter<O> messageConverter = new SimpleMessageConverter<>();
        Message<O> oMessage = messageConverter.toMessage(payload);

        doBroadcast(destination, oMessage);
    }

    @Override
    protected void doSendToUser(String  eventName, Message<?> message) {
        String to = message.getTo();
        SocketIOClient socketIOClient = clientRepository.get(to);
        if (socketIOClient != null) {
            socketIOClient.sendEvent(eventName, message);
        }
    }

    /**
     * Obtain namespace socket io namespace.
     *
     * @param namespaceName the namespace name
     * @return the socket io namespace
     */
    private SocketIONamespace obtainNamespace(String namespaceName) {
        return Optional.ofNullable(socketIOServer.getNamespace(namespaceName))
                .orElse(socketIOServer.addNamespace(namespaceName));
    }

    /**
     * Add event listener.
     *
     * @param <T>        the type parameter
     * @param namespace  the namespace
     * @param eventName  the event name
     * @param eventClass the event class
     */
    private <T> void addEventListener(SocketIONamespace namespace, String eventName, Class<T> eventClass) {
        namespace.addEventListener(eventName, eventClass, (client, data, ackSender) -> {

            if (ackSender.isAckRequested()) {
                ackSender.sendAckData("message has been delivered to server");
            }
            client.sendEvent(eventName, data);
        });
    }

}
